#include "tunnel.h"
// 生成唯一的邮箱键值
key_t generate_mail_key(int mailbox_index) {
    static const char* KEY_FILE =  "/tmp/mailbox_keys";  
    static const int PROJ_ID = 'A';                    // 项目标识符
    
    // 确保文件存在
    FILE* fp = fopen(KEY_FILE, "a");
    if (fp) fclose(fp);
    
    // 生成基键值
    key_t base_key = ftok(KEY_FILE, PROJ_ID);
    if (base_key == -1) {
        perror("ftok failed");
        exit(EXIT_FAILURE);
    }
    // 派生唯一键值 (基键值 + 邮箱索引)
    return base_key + mailbox_index;
}

void creat_tunnel_sem(Tunnel *t) {
    if (t->max_car_in <= 0) {
        printf("Error: max_car_in must be positive\n");
        exit(1);
    }
    if(t->max_car_in > 250){
        fprintf(stderr, "Creating tunnel semaphore with key=%d, max_car_in=%d\n", tunnel_key, t->max_car_in);
        printf("Error: max_car_in must be less than 250\n");
        exit(1); 
    }
    t->tun_car_semid = creat_sem(tunnel_key, t->max_car_in, 1); //计数信号量
}

void creat_mail_shared(Tunnel *t) {
    int i;
    t->mail_shmid = (int*)malloc(t->mail_sum * sizeof(int));
    for (i = 0; i < t->mail_sum; i++) {
        key_t current_key = generate_mail_key(i);
        t->mail_shmid[i] = create_shm(current_key, t->mail_size);
        //t->mail_shmid[i] = create_shm(mail_key_shm+i, t->mail_size); // 确保每个邮箱都有共享内存
    }
    
    t->readcount = create_shm(mail_read, sizeof(int) * t->mail_sum);
    t->writecount = create_shm(mail_write, sizeof(int) * t->mail_sum);

    int* read = (int*)get_shm(t->readcount);
    int* write = (int*)get_shm(t->writecount);
    for (i = 0; i < t->mail_sum; i++) {
        read[i] = 0;
        write[i] = 0;
    }
    disconnect_shm(read);
    disconnect_shm(write);
}

void creat_mail_sem(Tunnel *t) {
    int i;
    t->mail_semid = (int*)malloc(t->mail_sum * sizeof(int));
    for (i = 0; i < t->mail_sum; i++) {
        t->mail_semid[i] = creat_sem(mail_key_sem + i, 1, 5);
    }
}

void print_memory(Tunnel *t) {
    printf("========================================\n");
    int i;
    for (i = 0; i < t->mail_sum; i++) {
        char* message = (char*)get_shm(t->mail_shmid[i]);
        if (strlen(message)) {
            printf("Mailbox[%d]'s content is:%s\n", i, message);
        } else {
            printf("Mailbox[%d]'s content is:NULL\n", i);
        }
        disconnect_shm(message);
    }
    del_tunnel_sem(t);
    del_mail_shared(t);
    del_mail_sem(t);
}

void del_tunnel_sem(Tunnel *t) {
    delete_sem(t->tun_car_semid);
}

void del_mail_shared(Tunnel *t) {
    int i;
    for (i = 0; i < t->mail_sum; i++) {
        delete_shm(t->mail_shmid[i]);
    }
    delete_shm(t->readcount);
    delete_shm(t->writecount);
    free(t->mail_shmid);
}

void del_mail_sem(Tunnel *t) {
    int i;
    for (i = 0; i < t->mail_sum; i++) {
        delete_sem(t->mail_semid[i]);
    }
    free(t->mail_semid);
}

Tunnel* create_tunnel(int max_car, int mail_sum, int mail_size, int travel_time) {
    Tunnel *t = (Tunnel*)malloc(sizeof(Tunnel));
    t->max_car_in = max_car;
    t->mail_size = mail_size;
    t->mail_sum = mail_sum;
    t->travel_time = travel_time;

    creat_tunnel_sem(t);
    creat_mail_shared(t);
    creat_mail_sem(t);
    #ifdef DEBUG
    printf("mail create success\n");
    #endif
    int mykey = generate_mail_key(mail_sum); 
    t->tun_shmid = create_shm(mykey, 2*sizeof(int)); // 存方向+双向计数
    t->current_direction = (int*)get_shm(t->tun_shmid); // 前两个int存方向
    t->car_in = t->current_direction + 1; // 第三个int存车辆数
    *t->current_direction = -1; // 自由通行
    *t->car_in = 0; // 初始车辆数为0
    //disconnect_shm(t->current_direction); //由于需要频繁读写，这里不分离

    t->tun_dir_semid = creat_sem(tun_dir_key, 2, 1); // 二进制信号量，用于切换方向
    return t;
}

void init_traffic_light(Tunnel *t) {
    int mykey = generate_mail_key(t->mail_sum + 1);
    t->light_shmid = create_shm(mykey, sizeof(int) * 3); // 存方向+双向计数
    t->waiting_counts = (int*)get_shm(t->light_shmid);
    t->traffic_light = t->waiting_counts + 2; // 前两个int存计数，第三个存方向

    // 初始化方向灯状态
    *t->traffic_light = 0; // 默认方向A
    t->waiting_counts[0] = 0; // 方向A等待数
    t->waiting_counts[1] = 0; // 方向B等待数
    //disconnect_shm(t->waiting_counts); //由于需要频繁读写，这里不分离

    // 创建保护方向灯的信号量
    t->light_semid = creat_sem(light_sem_key, 1, 1); // 二进制信号量
    t->light_switch_time = 20; // 20秒切换一次
    t->last_switch_time = time(NULL);
}

void traffic_light_controller(Tunnel *t) {
    while (1) {
        update_traffic_light(t);
        sleep(1); // 每秒检查一次
    }
}
// 根据等待车辆数动态调整切换时间
void update_light_switch_time(Tunnel *t) {
    int total_waiting = t->waiting_counts[0] + t->waiting_counts[1];
    t->light_switch_time = total_waiting > 5 ? 10 : 30; // 拥堵时缩短切换时间
}
#ifdef SMART_LIGHT_CONTROL
void update_traffic_light(Tunnel *t) {
    // 获取红绿灯锁，确保线程安全
    Wait(t->light_semid, 0);
    
    time_t now = time(NULL);
    int current_dir = *t->traffic_light;
    int opposite_dir = 1 - current_dir;
    
    // 计算当前方向和对向方向的等待车辆数
    int current_waiting = t->waiting_counts[current_dir];
    int opposite_waiting = t->waiting_counts[opposite_dir];
    
    // 条件1：基于时间的切换（基础条件）
    if (now - t->last_switch_time >= t->light_switch_time) {
        // 只有当对向有车时才切换，避免无意义切换
        if (opposite_waiting > 0) {
            *t->traffic_light = opposite_dir;
            t->last_switch_time = now;
            printf("[Light] Time-based switch to direction %d (waiting: %d->%d)\n", 
                  opposite_dir, current_waiting, opposite_waiting);
            
            // 根据交通流量动态调整切换时间
            update_light_switch_time(t);
        } else {
            // 延长当前方向的绿灯时间
            t->last_switch_time = now;
            printf("[Light] Extending direction %d (no opposite traffic)\n", current_dir);
        }
    }
    // 条件2：智能切换条件
    else {
        // 2a: 当前方向无车且对向有车等待
        if (t->cars_in == 0 && opposite_waiting > 0) {
            *t->traffic_light = opposite_dir;
            t->last_switch_time = now;
            printf("[Light] Smart switch to direction %d (current empty, opposite waiting: %d)\n",
                  opposite_dir, opposite_waiting);
            
            update_light_switch_time(t);
        }
        // 2b: 当前方向车流已清空且时间接近切换点
        else if (t->cars_in == 0 && 
                (now - t->last_switch_time) >= (t->light_switch_time - 5)) {
            *t->traffic_light = opposite_dir;
            t->last_switch_time = now;
            printf("[Light] Early switch to direction %d (current empty, time nearly up)\n",
                  opposite_dir);
            
            update_light_switch_time(t);
        }
        // 2c: 对向车辆积压严重（超过阈值）
        else if (opposite_waiting >= 10 && current_waiting <= 2) {
            *t->traffic_light = opposite_dir;
            t->last_switch_time = now;
            printf("[Light] Emergency switch to direction %d (heavy opposite traffic: %d)\n",
                  opposite_dir, opposite_waiting);
            
            // 缩短下次切换时间以缓解拥堵
            t->light_switch_time = 5;
        }
    }
    
    // 释放锁
    Signal(t->light_semid, 0);
}
#else
void update_traffic_light(Tunnel *t) {
    Wait(t->light_semid, 0); // 获取红绿灯锁
    
    time_t now = time(NULL);
    #ifdef DEBUG
    printf("[Light] Current direction: %d, Waiting counts: A=%d, B=%d\n",
          *t->traffic_light, t->waiting_counts[0], t->waiting_counts[1]);
    #endif
    int opposite_dir = 1 - (*t->traffic_light); // 对向方向
    
    // 条件1：基于时间的切换
    if (now - t->last_switch_time >= t->light_switch_time) {
        *t->traffic_light = opposite_dir;
        t->last_switch_time = now;
        printf("[Light] Switched to direction %d (Time-based).\n", opposite_dir);
    }
    // 条件2：基于流量的切换（当前方向无车，对向有车）
    else if (*t->car_in == 0 && t->waiting_counts[opposite_dir] > 0) {
        *t->traffic_light = opposite_dir;
        t->last_switch_time = now;
        printf("[Light] Switched to direction %d (Traffic-based).\n", *t->traffic_light);
    }
    Signal(t->light_semid, 0); // 释放锁
}
#endif
void del_traffic_light(Tunnel *t) {
    delete_sem(t->light_semid);
    delete_shm(t->light_shmid);
}
void destroy_tunnel(Tunnel *t) {
    //disconnect_shm(t->current_direction);
    //disconnect_shm(t->car_in);
    delete_sem(t->tun_dir_semid);
    delete_shm(t->tun_shmid);
    free(t);
}
